package com.gupaoedu.vip;

import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.net.Socket;
import java.util.Map;

/**
 * <p>
 *
 * </p>
 *
 * @author Nicky
 * @since 2019-10-05
 */
public class ProcesserHander implements Runnable {

  private Socket socket;

  private Map<String,Object> handlerBeanMap;

  public ProcesserHander(Socket socket, Map<String,Object> handlerBeanMap) {
    this.socket = socket;
    this.handlerBeanMap = handlerBeanMap;
  }

  /**
   * When an object implementing interface <code>Runnable</code> is used
   * to create a thread, starting the thread causes the object's
   * <code>run</code> method to be called in that separately executing
   * thread.
   * <p>
   * The general contract of the method <code>run</code> is that it may
   * take any action whatsoever.
   *
   * @see Thread#run()
   */
  @Override
  public void run() {
    ObjectInputStream objectInputStream = null;
    ObjectOutputStream objectOutputStream = null;

    try {
      objectInputStream = new ObjectInputStream(socket.getInputStream());
      RpcRequest request = (RpcRequest)objectInputStream.readObject();
      Object result = invoke(request);

      objectOutputStream = new ObjectOutputStream(socket.getOutputStream());
      objectOutputStream.writeObject(result);
      objectOutputStream.flush();

    } catch (IOException e) {
      e.printStackTrace();
    } catch (ClassNotFoundException e) {
      e.printStackTrace();
    } catch (NoSuchMethodException e) {
      e.printStackTrace();
    } catch (IllegalAccessException e) {
      e.printStackTrace();
    } catch (InvocationTargetException e) {
      e.printStackTrace();
    }
    finally {
      if(objectInputStream !=null){
        try {
          objectInputStream.close();
        } catch (IOException e) {
          e.printStackTrace();
        }
      }
      if(objectOutputStream != null){
        try {
          objectOutputStream.close();
        } catch (IOException e) {
          e.printStackTrace();
        }
      }
    }
  }

  private Object invoke(RpcRequest request) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, IllegalAccessException {
    String serviceName = request.getClassName();

    Object service = handlerBeanMap.get(serviceName);
    if(service==null){
      throw new RuntimeException("service not found" + serviceName);
    }

    Object[] args = request.getParmters();
    Class<?>[] types = new Class[args.length];
    for (int i = 0; i < args.length ; i++) {
      types[i] = args[i].getClass();
    }
    Class clazz = Class.forName(request.getClassName());
    Method method = clazz.getMethod(request.getMethodName(),types);
    Object result = method.invoke(service,args);
    return result;
  }
}
